package cn.itcode_03;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Aaron
 * @since 2021/3/26 10:30
 * <p>描述：</p>
 */
public class FairAndUnfairTest {
    private static final Lock FAIR_LOCK = new ReentrantLock2(true);
    private static final Lock UNFAIR_LOCK = new ReentrantLock2(false);
    private static CyclicBarrier cyclicBarrier = null;

    public static void main(String[] args) throws InterruptedException {
        // 每次只测试一种锁，效果更好
        FairAndUnfairTest fairAndUnfairTest = new FairAndUnfairTest();
        System.out.println("---------公平锁测试--------");
        fairAndUnfairTest.testLock(FAIR_LOCK);

        TimeUnit.SECONDS.sleep(3);

        System.out.println("---------非公平锁测试--------");
        fairAndUnfairTest.testLock(UNFAIR_LOCK);
    }

    private void testLock(Lock lock) {
        cyclicBarrier = new CyclicBarrier(5);
        for (int i = 0; i < 5; i++) {
            Thread thread = new Job(lock);
            thread.setName("" + i);
            thread.start();
        }
    }

    private static class Job extends Thread {
        private final Lock lock;

        public Job(Lock lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }

            for (int i = 0; i < 2; i++) {
                lock.lock();
                try {
                    System.out.println("Lock by [" + getName() + "], Waiting by " + ((ReentrantLock2) lock).getQueuedThreads());
                } finally {
                    lock.unlock();
                }
            }
        }

        @Override
        public String toString() {
            return getName();
        }
    }

    /**
     * 重写重入锁 ReentrantLock，添加获取等待队列线程的方法
     */
    private static class ReentrantLock2 extends ReentrantLock {
        private static final long serialVersionUID = -6736727496956351588L;

        public ReentrantLock2(boolean fair) {
            super(fair);
        }

        @Override
        public Collection<Thread> getQueuedThreads() {
            List<Thread> arrayList = new ArrayList<>(super.getQueuedThreads());
            Collections.reverse(arrayList);
            return arrayList;
        }
    }

}
